package ru.neoflex.jedit.plugin.core;

import ru.neoflex.jedit.plugin.domain.autocomplete.XhtmlAutocompleteSettings;
import org.apache.commons.io.FileUtils;
import ru.neoflex.jedit.plugin.utils.Assert;
import ru.neoflex.jedit.plugin.ui.IWhisdomBar;
import org.gjt.sp.jedit.jEdit;
import org.gjt.sp.jedit.textarea.JEditTextArea;
import org.gjt.sp.util.Log;
import java.awt.Point;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.swing.SwingUtilities;
import ru.neoflex.jedit.plugin.ui.CompletionPopup;
import ru.neoflex.jedit.plugin.ui.ICompletionPopup;
import ru.neoflex.jedit.plugin.utils.XhtmlUtils;
import org.gjt.sp.jedit.textarea.TextArea;
import ru.neoflex.jedit.plugin.domain.autocomplete.XhtmlAutocompleteSettings.Tag;

public class NeoflexState {
    private static NeoflexState instance = new NeoflexState();

    public static NeoflexState getInstance() {
        return instance;
    }

    private XhtmlAutocompleteSettings xhtmlAutocompleteSettings = new XhtmlAutocompleteSettings();
    private XhtmlCaretListener xhtmlCaretListener = new XhtmlCaretListener();

    private PropertiesIndex propertiesIndex;

    private IWhisdomBar whisdomBar;

    public void reloadXhtmlAutocompleteSettings() throws IOException {
        String filename = getConfigDirectory() + XhtmlAutocompleteSettings.DEFAULT_CONFIG_NAME;
        File config = new File(filename);
        if (!config.exists()) {
            XhtmlAutocompleteSettings.createEmptyXml(filename);
        }

        xhtmlAutocompleteSettings = XhtmlAutocompleteSettings.loadFromXml(filename);
    }

    private String getConfigDirectory() throws IOException {
        File configDirectory = new File(FileUtils.getUserDirectoryPath() + File.separator + ".jneoflex" + File.separator);
        if (!configDirectory.exists()) {
            FileUtils.forceMkdir(configDirectory);
        }

        Assert.isTrue(configDirectory.exists());
        Assert.isTrue(configDirectory.isDirectory());

        return configDirectory.getAbsolutePath() + File.separator;
    }

    public XhtmlAutocompleteSettings getXhtmlAutocompleteSettings() {
        return xhtmlAutocompleteSettings;
    }

    public XhtmlCaretListener getHhtmlCaretListener() {
        return xhtmlCaretListener;
    }

    private ICompletionPopup thePopup;

    private void disposePopupIfVisible() {
        if (thePopup != null) {
            thePopup.dispose();
            thePopup = null;
        }
    }

    private List<Completion> getXhtmlAttributeCompletions(String tagName) {
        List<Completion> result = new ArrayList<Completion>();
        Tag tag = xhtmlAutocompleteSettings.getTagByName(tagName);
        if (tag != null) {
            for (XhtmlAutocompleteSettings.TagAttribute attr : tag.getAttributes()) {
                result.add(new Completion(attr.getName()));
            }
        }
        return result;
    }

    private List<Completion> getXhtmlTagCompletions() {
        List<Completion> result = new ArrayList<Completion>();
        for (Tag tag : xhtmlAutocompleteSettings.getTags()) {
            result.add(new Completion(tag.getName()));
        }
        return result;
    }

    private List<Completion> filterCompletions(List<Completion> completions, String prefix) {
        List<Completion> result = new ArrayList<Completion>();
        for (Completion completion : completions) {
            if (completion.getWord().startsWith(prefix)) {
                result.add(completion);
            }
        }
        return result;
    }

    public void showXhtmlAutocompletePopup() {
        JEditTextArea textArea = jEdit.getActiveView().getTextArea();
        String text = textArea.getText();
        int position = textArea.getCaretPosition();
        String prefix = XhtmlUtils.getPrefix(text, position);


        Log.log(Log.NOTICE, this, "prefix $prefix");

        if (XhtmlUtils.isTagEntered(text, position)) {
            String tag = XhtmlUtils.getTagName(text, position);
            Log.log(Log.NOTICE, this, "tag $tag");

            displayCompletionPopup(textArea, filterCompletions(getXhtmlAttributeCompletions(tag), prefix), prefix);
        } else {

            displayCompletionPopup(textArea, filterCompletions(getXhtmlTagCompletions(), prefix), prefix);
        }
    }

    private void displayCompletionPopup(TextArea textArea, List<Completion> completions, String thePrefix) {
        if (completions.size() >= 1) {
            if (thePopup == null) {

                textArea.scrollToCaret(false);
                Point location = textArea.offsetToXY(textArea.getCaretPosition() - thePrefix.length());
                location.y += textArea.getPainter().getFontMetrics().getHeight();

                SwingUtilities.convertPointToScreen(location, textArea.getPainter());

                this.thePopup = new CompletionPopup(jEdit.getActiveView(), location);

                thePopup.setWord(thePrefix);

                thePopup.showCompletions((Completion[]) completions.toArray());
                Log.log(Log.DEBUG, this, "displayCompletionPopup: popup displayed");
            } else {
                thePopup.setWord(thePrefix);
                thePopup.showCompletions((Completion[]) completions.toArray());

                Log.log(Log.DEBUG, this, "displayCompletionPopup: an already displayed popup updated");
            }

        }
        else {
            disposePopupIfVisible();
        }
    }

    public void rebuildPropertiesFileIndex() {
    }

    public IWhisdomBar getWhisdomBar() {
        return whisdomBar;
    }

    public void setWhisdomBar(IWhisdomBar whisdomBar) {
        this.whisdomBar = whisdomBar;
    }

    public String getHintForELExpression(String elExpression) {
        Assert.notBlank(elExpression);

        if (elExpression.toLowerCase().contains("msg") && elExpression.contains(".")) {
            //  Ищем в бандлах

            if (propertiesIndex == null) {
                whisdomBar.addNotification("Хотели бы поискать в файлах properties, да индекс не построен");
                return null;
            } else {
                if (elExpression.endsWith(".") && elExpression.indexOf(".") == elExpression.lastIndexOf(".")) {
                    //  Выводи bunld полностью
                    String bundleName = elExpression.replaceAll(".", "");
                    if (propertiesIndex.hasBundle(bundleName)) {
                        Map<String, Properties> result = propertiesIndex.getPropertiesByBundleName(bundleName);
                        if (result.size() > 0) {
                            StringBuilder sb = new StringBuilder();
                            for (String filePath : result.keySet()) {
                                sb.append("file:///" + filePath + "\n");
                                Properties props = result.get(filePath);
                                for (String key : props.stringPropertyNames()) {
                                    String value = props.getProperty(key);
                                    sb.append(key + "= " + value);
                                }
                            }
                            return sb.toString();
                        } else Assert.isTrue(false);
                    } else {
                        return "No bundle with name " + bundleName;
                    }
                } else {
                    //  Выводим значения из бандла
                    int dot = elExpression.indexOf(".");
                    String bundleName = elExpression.substring(0, dot);
                    String property = elExpression.substring(dot + 1);
                    Assert.notBlank(property);
                    if (propertiesIndex.hasBundle(bundleName)) {
                        Map<String, String> result = propertiesIndex.getPropertyValueFromBundle(bundleName, property);
                        if (result.size() > 0) {
                            StringBuilder sb = new StringBuilder();
                            for (String filePath : result.keySet()) {
                                String value = result.get(filePath);

                                sb.append(value + " (" + filePath + ")");
                            }
                            return sb.toString();
                        } else Assert.isTrue(false);
                    } else {
                        return "No bundle with name " + bundleName;
                    }
                }
            }
        } else {
            //  Ищем в бинах

            return "Beans search is not implemented yet";
        }
        return "Error";
    }
}
